package com.spsoft.vatoutinv.service.issueinvoice.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.spsoft.core.enums.ResponseEnum;
import com.spsoft.core.model.Result;
import com.spsoft.core.utils.StringUtil;
import com.spsoft.vatoutinv.constants.CommonConstant;
import com.spsoft.vatoutinv.constants.DictConstant;
import com.spsoft.vatoutinv.entity.vmsclassifycode.VmsClassifyCode;
import com.spsoft.vatoutinv.entity.vmsenterpriseinfo.VmsEnterpriseInfo;
import com.spsoft.vatoutinv.entity.vmsepsInformation.VmsEpsInformation;
import com.spsoft.vatoutinv.entity.vmsfulloutinvoice.*;
import com.spsoft.vatoutinv.entity.vmshzqrdmanage.VmsLeqiHzqrd;
import com.spsoft.vatoutinv.enums.CheckParamEnum;
import com.spsoft.vatoutinv.enums.CommonEnum;
import com.spsoft.vatoutinv.enums.JtysgjlxEnum;
import com.spsoft.vatoutinv.enums.ZjlxEnum;
import com.spsoft.vatoutinv.model.dto.vmsfulloutinvoice.VmsFullOutInvoiceInfoDto;
import com.spsoft.vatoutinv.model.vo.issueinvoice.ErrorVerifyVo;
import com.spsoft.vatoutinv.service.issueinvoice.CheckDataService;
import com.spsoft.vatoutinv.service.issueinvoice.PriceTaxSeparationService;
import com.spsoft.vatoutinv.service.translate.impl.DictTranslate;
import com.spsoft.vatoutinv.service.vmsclassifycode.VmsClassifyCodeService;
import com.spsoft.vatoutinv.service.vmsdifferentialcode.VmsDifferentialCodeService;
import com.spsoft.vatoutinv.service.vmsenterpriseinfo.VmsEnterpriseInfoService;
import com.spsoft.vatoutinv.service.vmsepsInformation.VmsEpsInformationService;
import com.spsoft.vatoutinv.service.vmshzqrdmanage.VmsLeqiHzqrdService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;

/**
 * 数据校验接口实现类
 *
 * @author : chenxudong
 * @date : 2024/3/27 18:37
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class CheckDataServiceImpl implements CheckDataService {

    public static final String LOG_MSG = "(数据校验实现层)";

    private final VmsEnterpriseInfoService vmsEnterpriseInfoService;

    private final VmsEpsInformationService vmsEpsInformationService;

    private final VmsClassifyCodeService vmsClassifyCodeService;

    private final VmsDifferentialCodeService vmsDifferentialCodeService;

    private final PriceTaxSeparationService priceTaxSeparationService;

    private final VmsLeqiHzqrdService vmsLeqiHzqrdService;

    private final DictTranslate dictTranslate;

    @Override
    public List<ErrorVerifyVo> checkDataBusiness(List<VmsFullOutInvoiceInfoDto> invoiceDtoList, String deptCode, String checkSource) {
        List<ErrorVerifyVo> errorVerifyList = new ArrayList<>();

        for (int i = 0; i < invoiceDtoList.size(); i++) {
            VmsFullOutInvoiceInfoDto invoice = invoiceDtoList.get(i);
            VmsFullOutInvoiceDetails invoiceDetails = invoice.getVmsFullOutInvoiceDetails();
            List<VmsFullOutInvoiceItems> invoiceItemsList = invoice.getVmsFullOutInvoiceItemsList();
            VmsFullOutInvoiceItemsExp invoiceItemsExp = invoice.getVmsFullOutInvoiceItemsExp();

            // 参数校验返回值
            String errMsg;
            String num;
            String key;

            if (CommonEnum.CHECK_SOURCE_0.getKey().equals(checkSource)) {
                num = "手工开票";
                key = "发票主信息";
            } else if (CommonEnum.CHECK_SOURCE_1.getKey().equals(checkSource)) {
                num = "手工开票基础信息";
                key = "第" + (i + 4) + "行";
            } else {
                num = "第" + (i + 1) + "张发票";
                key = "发票主信息";
            }

            // 发票主信息、明细信息必填校验，为空直接返回
            if (ObjectUtil.isEmpty(invoiceDetails)) {
                errMsg = ResponseEnum.TAXSEPARATION_NULL2.getMsg();
                ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                errorVerifyList.add(errorVerify);
                return errorVerifyList;
            }
            if (CollectionUtil.isEmpty(invoiceItemsList)) {
                errMsg = ResponseEnum.TAXSEPARATION_NULL5.getMsg();
                ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                errorVerifyList.add(errorVerify);
                return errorVerifyList;
            }

            // 手工开票只能开蓝字发票
            if (CommonEnum.CHECK_SOURCE_0.getKey().equals(checkSource)) {
                if (invoiceDetails.getHjje().compareTo(BigDecimal.ZERO) <= 0) {
                    errMsg = ResponseEnum.SGKP_JSHJ_ERROR.getMsg();
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                    errorVerifyList.add(errorVerify);
                }
            }

            // Excel导入开票只能开蓝字发票
            if (CommonEnum.CHECK_SOURCE_1.getKey().equals(checkSource)) {
                if (invoiceDetails.getHjje().compareTo(BigDecimal.ZERO) <= 0) {
                    errMsg = ResponseEnum.EXCEL_JSHJ_ERROR.getMsg();
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                    errorVerifyList.add(errorVerify);
                }
            }

            // 红票业务逻辑校验
            if (CommonEnum.INVOICE_RED.getKey().equals(invoiceDetails.getLzfpbz())) {
                // 对应蓝字发票号码
                if (StringUtils.isBlank(invoiceDetails.getDylzfphm())) {
                    errMsg = ResponseEnum.RED_DYLZFPHM_EMPTY_ERROR.getMsg();
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                    errorVerifyList.add(errorVerify);
                }
                // 红字确认单编号
                if (StringUtils.isBlank(invoiceDetails.getHzqrxxdbh())) {
                    errMsg = ResponseEnum.RED_HZQRDBH_EMPTY_ERROR.getMsg();
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                    errorVerifyList.add(errorVerify);
                }
                // 红字确认单uuid
                if (StringUtils.isBlank(invoiceDetails.getHzqrduuid())) {
                    errMsg = ResponseEnum.RED_HZQRDUUID_EMPTY_ERROR.getMsg();
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                    errorVerifyList.add(errorVerify);
                }
                // 作废红冲原因
                if (StringUtils.isBlank(invoiceDetails.getZfchyy())) {
                    errMsg = ResponseEnum.RED_ZFCHYY_EMPTY_ERROR.getMsg();
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                    errorVerifyList.add(errorVerify);
                }
                // 作废红冲日期
                if (invoiceDetails.getZfchrq() == null) {
                    errMsg = ResponseEnum.RED_ZFCHRQ_EMPTY_ERROR.getMsg();
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                    errorVerifyList.add(errorVerify);
                }
                // 开票金额
                if (invoiceDetails.getJshj().compareTo(BigDecimal.ZERO) > 0) {
                    errMsg = ResponseEnum.RED_KPJE_ERROR.getMsg();
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                    errorVerifyList.add(errorVerify);
                }

                // 判断红字确认单编号是否已开具
                if (StringUtils.isNotBlank(invoiceDetails.getHzqrxxdbh())) {
                    LambdaQueryWrapper<VmsLeqiHzqrd> query = new LambdaQueryWrapper<>();
                    query.eq(VmsLeqiHzqrd::getHzfpxxqrdbh, invoiceDetails.getHzqrxxdbh());
                    query.eq(VmsLeqiHzqrd::getQydjid, deptCode);
                    VmsLeqiHzqrd leqiHzqrd = vmsLeqiHzqrdService.getOne(query);
                    // 有效标志为N，说明红字确认单已失效，不允许开具
                    if (leqiHzqrd != null && CommonEnum.HZQRD_YXBZ_NO.getKey().equals(leqiHzqrd.getYxbz())) {
                        errMsg = ResponseEnum.HZQRD_FAILURE_ERROR.getMsg();
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                        errorVerifyList.add(errorVerify);
                    }
                    // 已开具红字发票标志为Y，已开具、数电发票表主键不为空，已开具
                    if (leqiHzqrd != null && (CommonEnum.YKJHZFP_YES.getKey().equals(leqiHzqrd.getYkjhzfpbz()) || ObjectUtil.isNotEmpty(leqiHzqrd.getFoidid()))) {
                        errMsg = ResponseEnum.HZQRD_USED_ERROR.getMsg();
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                        errorVerifyList.add(errorVerify);
                    }
                }

                // 红票明细必填项校验
                for (int j = 0; j < invoiceItemsList.size(); j++) {
                    VmsFullOutInvoiceItems invoiceItem = invoiceItemsList.get(j);
                    String key2 = "发票第" + (j + 1) + "行明细";
                    // 对应蓝字发票明细序号
                    if (invoiceItem.getDylzfpmxxh() == null || invoiceItem.getDylzfpmxxh() == 0) {
                        errMsg = ResponseEnum.RED_DYLZFPMXXH_EMPTY_ERROR.getMsg();
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key2, errMsg);
                        errorVerifyList.add(errorVerify);
                    }
                    // 开票金额
                    if (invoiceItem.getJe().compareTo(BigDecimal.ZERO) > 0) {
                        errMsg = ResponseEnum.RED_KPJE_ERROR.getMsg();
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key2, errMsg);
                        errorVerifyList.add(errorVerify);
                    }
                }
            }

            // 蓝票金额校验
            if (CommonEnum.INVOICE_BLUE.getKey().equals(invoiceDetails.getLzfpbz())) {
                // 开票金额需大于0
                if (invoiceDetails.getJshj().compareTo(BigDecimal.ZERO) <= 0) {
                    errMsg = ResponseEnum.BLUE_KPJE_ERROR.getMsg();
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                    errorVerifyList.add(errorVerify);
                }
            }

            // 流水开票、官网开票必填项校验
            if (CommonEnum.DATA_SOURCE_0.getKey().equals(invoiceDetails.getSjly())
                    || CommonEnum.DATA_SOURCE_2.getKey().equals(invoiceDetails.getSjly())) {
                // 流水开票明细必填项校验
                for (int j = 0; j < invoiceItemsList.size(); j++) {
                    VmsFullOutInvoiceItems invoiceItem = invoiceItemsList.get(j);
                    String key2 = "发票第" + (j + 1) + "行明细";
                    // 流水id
                    if (StringUtils.isBlank(invoiceItem.getRdid())) {
                        errMsg = ResponseEnum.LSKP_RDID_EMPTY_ERROR.getMsg();
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key2, errMsg);
                        errorVerifyList.add(errorVerify);
                    }
                }
            }

            /*
            购买方自然人标志校验
            当选择“是”时，【购买方名称】录入内容必须大于1个长度（一个汉字、数字、字母、符号）
            当选择“否”时，【购买方名称】录入内容必须大于4个长度（一个汉字、数字、字母、符号）
            */
            String gmfzrrbz = "";
            if (ObjectUtil.isNotNull(invoiceItemsExp)) {
                gmfzrrbz = invoiceItemsExp.getGmfzrrbz();
            }
            String gmfmc = invoiceDetails.getGmfmc();
            String fppz = invoiceDetails.getFppz();
            if (CommonEnum.INVOICE_TYPE_01.getKey().equals(fppz)) {
                // 数电专票自然人标志只能为否，且提示语特殊处理
                if (CommonEnum.PERSON_FLAG_02.getKey().equals(gmfzrrbz) && gmfmc.length() <= 4) {
                    errMsg = ResponseEnum.BUSINESS_GMFZRRBZ_03_ERROR.getMsg();
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                    errorVerifyList.add(errorVerify);
                }
            } else {
                // 数电普票自然人标志校验
                if (CommonEnum.PERSON_FLAG_01.getKey().equals(gmfzrrbz) && gmfmc.length() <= 1) {
                    errMsg = ResponseEnum.BUSINESS_GMFZRRBZ_01_ERROR.getMsg();
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                    errorVerifyList.add(errorVerify);
                }
                if (CommonEnum.PERSON_FLAG_02.getKey().equals(gmfzrrbz) && gmfmc.length() <= 4) {
                    errMsg = ResponseEnum.BUSINESS_GMFZRRBZ_02_ERROR.getMsg();
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                    errorVerifyList.add(errorVerify);
                }
            }

            /*
            购买方纳税人识别号校验
            若发票类型为“数电专票”，则为必填；
            若发票类型为“数电普票”，且其购买方名称含有“公司”、“事务所”等字眼时，则为必填；反之为非必填；
            限制录入20位英文大写和阿拉伯数字组合。
            开具发票时，填写的销售方纳税人识别号和购买方纳税人识别号不能相同，否则阻断发票上传；但行业代码为“68”开头的保险行业使用
            3060301010000000000、3060301990000000000、3060302010000000000、3060302020000000000、3060302030000000000、
            3060302040000000000、3060302990000000000 的商编开具发票时，允许使用相同的购销方纳税人识别号
            */
            String gmfnsrsbh = invoiceDetails.getGmfnsrsbh();
            String xsfnsrsbh = invoiceDetails.getXsfnsrsbh();
            if (CommonEnum.INVOICE_TYPE_01.getKey().equals(fppz) && StringUtils.isBlank(gmfnsrsbh)) {
                errMsg = ResponseEnum.BUSINESS_SDZ_GMFNSRSBH_ERROR.getMsg();
                ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                errorVerifyList.add(errorVerify);
            }
            if (CommonEnum.INVOICE_TYPE_02.getKey().equals(fppz) && StringUtils.isNotBlank(gmfmc)
                    && (gmfmc.contains("公司") || gmfmc.contains("事务所")) && StringUtils.isBlank(gmfnsrsbh)) {
                errMsg = ResponseEnum.BUSINESS_GSSWS_GMFNSRSBH_ERROR.getMsg();
                ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                errorVerifyList.add(errorVerify);
            }
            // 购买方自然人标识为否时，购买方纳税人识别号为必填项（新华的校验）
            if (CommonEnum.PERSON_FLAG_02.getKey().equals(gmfzrrbz) && StringUtils.isBlank(gmfnsrsbh)) {
                errMsg = ResponseEnum.GMFZRR_GMFNSRSBH_ERROR.getMsg();
                ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                errorVerifyList.add(errorVerify);
            }
            if (xsfnsrsbh.equals(gmfnsrsbh)) {
                boolean isError = false;
                VmsEnterpriseInfo infoResult = vmsEnterpriseInfoService.getInfoByRedis(deptCode);
                if (infoResult != null && StringUtils.isNotBlank(infoResult.getHydm())) {
                    String hydm = infoResult.getHydm();
                    if (hydm.startsWith("68")) {
                        List<String> list = Arrays.asList("3060301010000000000", "3060301990000000000", "3060302010000000000", "3060302020000000000", "3060302030000000000", "3060302040000000000", "3060302990000000000");
                        for (VmsFullOutInvoiceItems invoiceItem : invoiceItemsList) {
                            if (!list.contains(invoiceItem.getSphfwssflhbbm())) {
                                isError = true;
                                break;
                            }
                        }
                    } else {
                        isError = true;
                    }
                } else {
                    isError = true;
                }
                if (isError) {
                    errMsg = ResponseEnum.BUSINESS_XSF_GMFNSRSBH_ERROR.getMsg();
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                    errorVerifyList.add(errorVerify);
                }
            }

            // 开具发票明细行小于 2000 条
            if (CollectionUtil.isNotEmpty(invoiceItemsList)
                    && invoiceItemsList.size() >= 2000) {
                errMsg = ResponseEnum.BUSINESS_DETAIL_MAX_ERROR.getMsg();
                ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                errorVerifyList.add(errorVerify);
            }

            for (int j = 0; j < invoiceItemsList.size(); j++) {
                VmsFullOutInvoiceItems invoiceItem = invoiceItemsList.get(j);
                // Excel导入校验企业商品及服务编码
                if (CommonEnum.CHECK_SOURCE_1.getKey().equals(checkSource)) {
                    LambdaQueryWrapper<VmsEpsInformation> query = new LambdaQueryWrapper<>();
                    query.eq(VmsEpsInformation::getEpsCode, invoiceItem.getCpbm())
                            // 下边代码加上括号
                            .and(m -> m.nested(n -> n.eq(VmsEpsInformation:: getApplication, CommonConstant.STR_02)
                                    .like(VmsEpsInformation:: getJyjg, deptCode))
                                    .or()
                                    .eq(VmsEpsInformation:: getApplication, CommonConstant.STR_01));
                    VmsEpsInformation vmsEpsInformation = vmsEpsInformationService.getOne(query);
                    if (vmsEpsInformation == null) {
                        errMsg = ResponseEnum.EPSCODE_NOT_FOUND_ERROR.getMsg();
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, "发票第" + (j + 1) + "行明细", errMsg);
                        errorVerifyList.add(errorVerify);
                        // 如果未查询到企业商品及服务编码，不进行后续的校验
                        return errorVerifyList;
                    } else {
                        // 查询到企业商品及服务编码，补全数据进行后续的校验
                        if (StringUtils.isBlank(invoiceItem.getSphfwssflhbbm())) {
                            invoiceItem.setSphfwssflhbbm(vmsEpsInformation.getGstcmCode());
                        }
                        if (StringUtils.isBlank(invoiceItem.getXmmc())) {
                            invoiceItem.setXmmc(vmsEpsInformation.getEpsName());
                        }
                        if (StringUtils.isBlank(invoiceItem.getDw())) {
                            invoiceItem.setDw(dictTranslate.translate(DictConstant.VMS_JLDW, vmsEpsInformation.getJldw()));
                        }
                        if (StringUtils.isBlank(invoiceItem.getJsff())) {
                            invoiceItem.setJsff(vmsEpsInformation.getJsff());
                        }
                        if (StringUtils.isBlank(invoiceItem.getZsxm())) {
                            invoiceItem.setZsxm(vmsEpsInformation.getZsxm());
                        }
                        if (StringUtils.isBlank(invoiceItem.getYhzcbs())) {
                            invoiceItem.setYhzcbs(vmsEpsInformation.getYhzcbs());
                        }
                    }
                }

                // 校验机构的商品编码和可用税率是否可用
                Result<Object> result1 = vmsClassifyCodeService.queryCodeAndTax(invoiceItem.getSphfwssflhbbm(), invoiceItem.getSlv(), deptCode);
                if (!ResponseEnum.SUCCESS.getCode().equals(result1.getCode())) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, "发票第" + (j + 1) + "行明细", result1.getMessage());
                    errorVerifyList.add(errorVerify);
                }

                // 校验机构的商品编码是否可以差额开票
                if (StringUtils.isNotBlank(invoiceDetails.getCezslxdm())) {
                    Result<Object> result2 = vmsDifferentialCodeService.checkDifferentialCode(invoiceItem.getSphfwssflhbbm(),
                                            invoiceItem.getSlv(), invoiceDetails.getFppz(), invoiceDetails.getCezslxdm(), deptCode);
                    if (!ResponseEnum.SUCCESS.getCode().equals(result2.getCode())) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, "发票第" + (j + 1) + "行明细", result2.getMessage());
                        errorVerifyList.add(errorVerify);
                    }
                }

                // 校验项目名称是否正确，不正确则进行修正
                LambdaQueryWrapper<VmsClassifyCode> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(VmsClassifyCode::getSphfwssflhbbm, invoiceItem.getSphfwssflhbbm());
                queryWrapper.eq(VmsClassifyCode::getDeptCode, deptCode);
                VmsClassifyCode vmsClassifyCode = vmsClassifyCodeService.getOne(queryWrapper);
                if (vmsClassifyCode != null) {
                    // 如果项目名称为空,使用乐企返回数据进行补全,如果不为空,并且需要补全,则进行补全
                    String spmc = invoiceItem.getXmmc();
                    StringBuilder stringBuilder = new StringBuilder();
                    if (StringUtils.isBlank(spmc)) {
                        spmc = stringBuilder.append(CommonConstant.STRING_STAR).append(vmsClassifyCode.getSphfwfljc()).append(CommonConstant.STRING_STAR).append(vmsClassifyCode.getSphfwmc()).toString();
                    } else if (StringUtil.checkXmmc(spmc, vmsClassifyCode.getSphfwfljc())) {
                        spmc = stringBuilder.append(CommonConstant.STRING_STAR).append(vmsClassifyCode.getSphfwfljc()).append(CommonConstant.STRING_STAR).append(spmc).toString();
                    }
                    invoiceItem.setXmmc(spmc);
                }
            }

            // 手工开具蓝票进行价税分离校验
            if (CommonEnum.DATA_SOURCE_1.getKey().equals(invoiceDetails.getSjly())
                && CommonEnum.INVOICE_BLUE.getKey().equals(invoiceDetails.getLzfpbz())) {
                // 价税分离，统一将明细转换为不含税金额、税额，用于后续校验
                invoice = priceTaxSeparationService.priceTaxSeparation(invoice);
                log.info("{}价税分离后数据：{}", LOG_MSG, JSONObject.toJSONString(invoice));
            }

            // 差额开票校验
            if (CommonEnum.CEZS_02.getKey().equals(invoiceDetails.getCezslxdm())) {
                // 发票行只能为一行，且不可有其他行
                if (CollectionUtil.isNotEmpty(invoiceItemsList)
                        && invoiceItemsList.size() != 1) {
                    errMsg = ResponseEnum.CEZS_DETAIL_ERROR.getMsg();
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                    errorVerifyList.add(errorVerify);
                }
                // 发票行金额默认不含税模式
                if (!CommonConstant.STR_01.equals(invoiceDetails.getJems())) {
                    errMsg = ResponseEnum.CEZS_JEMS_ERROR.getMsg();
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                    errorVerifyList.add(errorVerify);
                }
                // 价税合计和扣除额为必填项
                if (CollectionUtil.isNotEmpty(invoiceItemsList)
                        && ObjectUtil.isEmpty(invoiceItemsList.get(0).getKce())) {
                    errMsg = ResponseEnum.CEZS_KCE_ERROR.getMsg();
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                    errorVerifyList.add(errorVerify);
                }

                // 蓝票差额扣除信息校验
                if (CommonEnum.INVOICE_BLUE.getKey().equals(invoiceDetails.getLzfpbz())) {
                    // 蓝票差额征税：0<扣除额<=含税金额
                    if (invoiceItemsList.get(0).getKce().compareTo(BigDecimal.ZERO) <= 0
                            || invoiceItemsList.get(0).getKce().compareTo(invoiceDetails.getJshj()) > 0) {
                        errMsg = ResponseEnum.CEZS_KCE_ERROR2.getMsg();
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                        errorVerifyList.add(errorVerify);
                    }

                    List<VmsFullOutInvoiceCekc> invoiceCekcList = invoice.getVmsFullOutInvoiceCekcList();
                    if (CollectionUtil.isEmpty(invoiceCekcList)) {
                        errMsg = ResponseEnum.CEZS_CEKC_EMPTY_ERROR.getMsg();
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                        errorVerifyList.add(errorVerify);
                    } else {
                        for (int j = 0; j < invoiceCekcList.size(); j++) {
                            VmsFullOutInvoiceCekc invoiceCekc = invoiceCekcList.get(j);
                            String key2 = "发票第" + (j + 1) + "行差额扣除信息";
                            if (CommonEnum.CEKC_PZLX_01.getKey().equals(invoiceCekc.getPzlx())) {
                                // 凭证类型为“数电票”时，必须录入数电票号码、开票日期、凭证合计金额、本次扣除金额
                                if (StringUtils.isBlank(invoiceCekc.getFphm()) || StringUtils.isBlank(invoiceCekc.getKjrq())
                                        || ObjectUtil.isEmpty(invoiceCekc.getPzhjje()) || ObjectUtil.isEmpty(invoiceCekc.getBckcje())) {
                                    errMsg = ResponseEnum.CEZS_CEKC_PZLX_01_ERROR.getMsg();
                                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key2, errMsg);
                                    errorVerifyList.add(errorVerify);
                                }
                            } else if (CommonEnum.CEKC_PZLX_02.getKey().equals(invoiceCekc.getPzlx())
                                    || CommonEnum.CEKC_PZLX_03.getKey().equals(invoiceCekc.getPzlx())) {
                                // 凭证类型为“增值税专用发票、增值税普通发票”时，必须录入发票代码、发票号码、开票日期、凭证合计金额、本次扣除金额
                                if (StringUtils.isBlank(invoiceCekc.getFpdm()) || StringUtils.isBlank(invoiceCekc.getFphm())
                                        || StringUtils.isBlank(invoiceCekc.getKjrq()) || ObjectUtil.isEmpty(invoiceCekc.getPzhjje())
                                        || ObjectUtil.isEmpty(invoiceCekc.getBckcje())) {
                                    errMsg = ResponseEnum.CEZS_CEKC_PZLX_02_ERROR.getMsg();
                                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key2, errMsg);
                                    errorVerifyList.add(errorVerify);
                                }
                            } else if (CommonEnum.CEKC_PZLX_08.getKey().equals(invoiceCekc.getPzlx())) {
                                // 凭证类型为“其他发票”时，必须录入凭证合计金额、本次扣除金额、备注
                                if (ObjectUtil.isEmpty(invoiceCekc.getPzhjje()) || ObjectUtil.isEmpty(invoiceCekc.getBckcje())
                                        || StringUtils.isBlank(invoiceCekc.getBz())) {
                                    errMsg = ResponseEnum.CEZS_CEKC_PZLX_03_ERROR.getMsg();
                                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key2, errMsg);
                                    errorVerifyList.add(errorVerify);
                                }
                            } else if (CommonEnum.CEKC_PZLX_04.getKey().equals(invoiceCekc.getPzlx())) {
                                // 凭证类型为“营业税发票”时，必须录入发票代码、发票号码、开票日期、凭证合计金额、本次扣除金额
                                if (StringUtils.isBlank(invoiceCekc.getFpdm()) || StringUtils.isBlank(invoiceCekc.getFphm())
                                        || StringUtils.isBlank(invoiceCekc.getKjrq()) || ObjectUtil.isEmpty(invoiceCekc.getPzhjje())
                                        || ObjectUtil.isEmpty(invoiceCekc.getBckcje())) {
                                    errMsg = ResponseEnum.CEZS_CEKC_PZLX_04_ERROR.getMsg();
                                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key2, errMsg);
                                    errorVerifyList.add(errorVerify);
                                }
                            } else if (CommonEnum.CEKC_PZLX_05.getKey().equals(invoiceCekc.getPzlx())
                                    || CommonEnum.CEKC_PZLX_06.getKey().equals(invoiceCekc.getPzlx())
                                    || CommonEnum.CEKC_PZLX_07.getKey().equals(invoiceCekc.getPzlx())) {
                                // 凭证类型为“财政票据、法院裁决书、契税完税凭证”时，必须录入凭证合计金额、本次扣除金额
                                if (ObjectUtil.isEmpty(invoiceCekc.getPzhjje()) || ObjectUtil.isEmpty(invoiceCekc.getBckcje())) {
                                    errMsg = ResponseEnum.CEZS_CEKC_PZLX_05_ERROR.getMsg();
                                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key2, errMsg);
                                    errorVerifyList.add(errorVerify);
                                }
                            } else if (CommonEnum.CEKC_PZLX_09.getKey().equals(invoiceCekc.getPzlx())) {
                                // 凭证类型为“其他扣除凭证”时，必须录入凭证合计金额、本次扣除金额、备注，凭证名称录入“备注”
                                if (ObjectUtil.isEmpty(invoiceCekc.getPzhjje()) || ObjectUtil.isEmpty(invoiceCekc.getBckcje())
                                        || StringUtils.isBlank(invoiceCekc.getBz())) {
                                    errMsg = ResponseEnum.CEZS_CEKC_PZLX_06_ERROR.getMsg();
                                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key2, errMsg);
                                    errorVerifyList.add(errorVerify);
                                }
                            } else {
                                errMsg = ResponseEnum.CEZS_CEKC_PZLX_07_ERROR.getMsg();
                                ErrorVerifyVo errorVerify = buildErrorVerify(num, key2, errMsg);
                                errorVerifyList.add(errorVerify);
                            }

                            // 本次扣除金额需要小于等于凭证合计金额
                            if (ObjectUtil.isNotEmpty(invoiceCekc.getBckcje()) && ObjectUtil.isNotEmpty(invoiceCekc.getPzhjje())
                                    && invoiceCekc.getBckcje().compareTo(invoiceCekc.getPzhjje()) > 0) {
                                errMsg = ResponseEnum.CEZS_CEKC_PZLX_08_ERROR.getMsg();
                                ErrorVerifyVo errorVerify = buildErrorVerify(num, key2, errMsg);
                                errorVerifyList.add(errorVerify);
                            }
                        }
                    }
                }

                /*
                差额征税-差额开票：|(含税金额-扣除额)÷(1+税率)*税率-税额|<=0.06
                差额征税：金额=含税金额-税额
                */
                if (CollectionUtil.isNotEmpty(invoiceItemsList)) {
                    BigDecimal jshj = invoiceDetails.getJshj();
                    BigDecimal kce = invoiceItemsList.get(0).getKce();
                    BigDecimal slv = invoiceItemsList.get(0).getSlv();

                    // 差额
                    BigDecimal ce = jshj.subtract(kce);
                    // 不含税差额
                    BigDecimal bhsce = ce.divide(BigDecimal.ONE.add(slv), 13, RoundingMode.HALF_UP);
                    // 税额
                    BigDecimal se = bhsce.multiply(slv).setScale(2, RoundingMode.HALF_UP);
                    // 误差税额
                    BigDecimal wcse = se.subtract(invoiceItemsList.get(0).getSe());
                    if (wcse.abs().compareTo(new BigDecimal(CommonConstant.STR_006)) > 0) {
                        errMsg = ResponseEnum.CEZS_SE_ERROR.getMsg();
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                        errorVerifyList.add(errorVerify);
                    }

                    BigDecimal bhsje = jshj.subtract(se).setScale(2, RoundingMode.HALF_UP);
                    if (bhsje.compareTo(invoiceItemsList.get(0).getJe()) != 0) {
                        errMsg = ResponseEnum.CEZS_JE_ERROR.getMsg();
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                        errorVerifyList.add(errorVerify);
                    }
                }
                // 差额开票不再进行后续金额税额校验
            } else {
                /*
                    非差额开票校验：
                    单行金额校验：|单价*数量-金额|<=0.01。
                    单行税额校验：|金额*税率-税额|<=0.06。
                    汇总金额校验：|所有商品行金额之和-合计金额|<=0.01。
                    汇总税额校验：|金额*税率（第1行+......+金额*税率（第N行）-税额合计|<=1.27。
                */
                // 汇总金额、汇总税额
                BigDecimal hzje = BigDecimal.ZERO;
                BigDecimal hzse = BigDecimal.ZERO;
                int number = 1;
                for (VmsFullOutInvoiceItems invoiceItem : invoiceItemsList) {
                    // 单行金额校验
                    if (StringUtils.isNotBlank(invoiceItem.getDj()) && StringUtils.isNotBlank(invoiceItem.getSl())) {
                        // 单行金额校验：|单价*数量-金额|<=0.01
                        BigDecimal xmje = new BigDecimal(invoiceItem.getDj()).multiply(new BigDecimal(invoiceItem.getSl()));
                        BigDecimal jewc = xmje.subtract(invoiceItem.getJe()).setScale(2, RoundingMode.HALF_UP);
                        if (jewc.abs().compareTo(new BigDecimal(CommonConstant.STR_001)) > 0) {
                            errMsg = ResponseEnum.BUSINESS_DETAIL_JE_ERROR.getMsg();
                            ErrorVerifyVo errorVerify = buildErrorVerify(num, "发票第" + number + "行明细", errMsg);
                            errorVerifyList.add(errorVerify);
                        }
                    }
                    // 单行税额校验
                    BigDecimal xmse = invoiceItem.getJe().multiply(invoiceItem.getSlv());
                    BigDecimal sewc = xmse.subtract(invoiceItem.getSe()).setScale(2, RoundingMode.HALF_UP);
                    // 单行税额校验：|金额*税率-税额|<=0.06
                    if (sewc.abs().compareTo(new BigDecimal(CommonConstant.STR_006)) > 0) {
                        errMsg = ResponseEnum.BUSINESS_DETAIL_SE_ERROR.getMsg();
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, "发票第" + number + "行明细", errMsg);
                        errorVerifyList.add(errorVerify);
                    }

                    hzje = hzje.add(invoiceItem.getJe());
                    hzse = hzse.add(xmse);
                    number++;
                }

                // 合计金额、合计税额、价税合计
                BigDecimal hjje = invoiceDetails.getHjje();
                BigDecimal hjse = invoiceDetails.getHjse();
                BigDecimal jshj = invoiceDetails.getJshj();

                // 流水开票、官网开票价税合计与合计金额、合计税额校验
                if (jshj.compareTo(hjje.add(hjse)) != 0) {
                    errMsg = ResponseEnum.BUSINESS_JSHJ_ERROR.getMsg();
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                    errorVerifyList.add(errorVerify);
                }

                // 汇总金额校验：|所有商品行金额之和-合计金额|<=0.01
                BigDecimal jewc = hzje.subtract(hjje).setScale(2, RoundingMode.HALF_UP);
                if (jewc.abs().compareTo(new BigDecimal(CommonConstant.STR_001)) > 0) {
                    errMsg = ResponseEnum.BUSINESS_DETAIL_HZJE_ERROR.getMsg();
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                    errorVerifyList.add(errorVerify);
                }
                // 汇总税额校验：|金额 * 税率（第 1 行）+......+金额 * 税率（第 N 行）-税额合计| <= 1.27
                BigDecimal sewc = hzse.subtract(hjse).setScale(2, RoundingMode.HALF_UP);
                if (sewc.abs().compareTo(new BigDecimal(CommonConstant.STR_127)) > 0) {
                    errMsg = ResponseEnum.BUSINESS_DETAIL_HZSE_ERROR.getMsg();
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                    errorVerifyList.add(errorVerify);
                }
            }

            // 特定要素的特定业务信息校验（只校验蓝票）
            if (CommonEnum.INVOICE_BLUE.getKey().equals(invoiceDetails.getLzfpbz())) {
                // 不动产销售服务发票
                if (CommonEnum.TDYS_05.getKey().equals(invoiceDetails.getTdys())) {
                    List<ErrorVerifyVo> errorList = checkBdcxs(num, invoice);
                    if (CollectionUtil.isNotEmpty(errorList)) {
                        errorVerifyList.addAll(errorList);
                    }
                }
                // 不动产租赁服务发票
                if (CommonEnum.TDYS_06.getKey().equals(invoiceDetails.getTdys())) {
                    List<ErrorVerifyVo> errorList = checkBdczl(num, invoice);
                    if (CollectionUtil.isNotEmpty(errorList)) {
                        errorVerifyList.addAll(errorList);
                    }
                }
                // 旅客运输服务发票
                if (CommonEnum.TDYS_09.getKey().equals(invoiceDetails.getTdys())) {
                    List<ErrorVerifyVo> errorList = checkLkys(num, invoice);
                    if (CollectionUtil.isNotEmpty(errorList)) {
                        errorVerifyList.addAll(errorList);
                    }
                }
            }
        }

        return errorVerifyList;
    }

    /**
     * 校验不动产销售特定业务信息
     * @param num 第几张发票
     * @param invoice 开票数据
     * @return 校验结果
     */
    private List<ErrorVerifyVo> checkBdcxs(String num, VmsFullOutInvoiceInfoDto invoice) {
        List<ErrorVerifyVo> errorVerifyList = new ArrayList<>();
        String key = "不动产销售特定业务信息";
        String errMsg;

        if (CollectionUtil.isEmpty(invoice.getVmsFullOutInvoiceTdywList())) {
            errMsg = ResponseEnum.BDCXS_TDYW_EMPTY_ERROR.getMsg();
            ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
            errorVerifyList.add(errorVerify);
            return errorVerifyList;
        }

        // 不动产销售服务发票仅支持单行开具
        List<VmsFullOutInvoiceItems> invoiceItemsList = invoice.getVmsFullOutInvoiceItemsList();
        if (CollectionUtil.isNotEmpty(invoiceItemsList) && invoiceItemsList.size() != 1) {
            errMsg = ResponseEnum.BDCXS_ITEM_ERROR.getMsg();
            ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
            errorVerifyList.add(errorVerify);
        }
        // 不动产销售服务发票，单位、单价、数量必填
        VmsFullOutInvoiceItems invoiceItem = invoiceItemsList.get(0);
        if (StringUtils.isBlank(invoiceItem.getDw()) || StringUtils.isBlank(invoiceItem.getDj())
                || StringUtils.isBlank(invoiceItem.getSl())) {
            errMsg = ResponseEnum.BDCXS_DW_DJ_SL_ERROR.getMsg();
            ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
            errorVerifyList.add(errorVerify);
        }

        // 不动产销售服务发票的特定业务只有第一条
        VmsFullOutInvoiceTdyw invoiceTdyw = invoice.getVmsFullOutInvoiceTdywList().get(0);

        if (!StringUtil.checkStrLength(invoiceTdyw.getBdczldzS(), 1, 20)) {
            errMsg = ResponseEnum.BDCXS_BDCZLDZS_ERROR.getMsg();
            ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
            errorVerifyList.add(errorVerify);
        }
        if (Arrays.stream(new String[]{"省", "自治区", "特别行政区", "北京市", "天津市", "上海市", "重庆市"}).noneMatch(keyWord -> invoiceTdyw.getBdczldzS().endsWith(keyWord))) {
            errMsg = ResponseEnum.BDCXS_BDCZLDZS_ERROR2.getMsg();
            ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
            errorVerifyList.add(errorVerify);
        }
        if (StrUtil.equalsAny(invoiceTdyw.getBdczldzS(), "香港特别行政区", "澳门特别行政区", "台湾省")) {
            if (!StringUtil.checkStrLength(invoiceTdyw.getBdczldzS1(), 0, 20)) {
                errMsg = ResponseEnum.BDCXS_BDCZLDZS1_ERROR.getMsg();
                ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                errorVerifyList.add(errorVerify);
            }
        } else {
            if (!StringUtil.checkStrLength(invoiceTdyw.getBdczldzS1(), 1, 20)) {
                errMsg = ResponseEnum.BDCXS_BDCZLDZS1_ERROR.getMsg();
                ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                errorVerifyList.add(errorVerify);
            }
        }
        if (StringUtils.isNotBlank(invoiceTdyw.getBdczldzS1())) {
            if (Arrays.stream(new String[]{"市", "盟", "自治州", "地区", "区"}).noneMatch(keyWord -> invoiceTdyw.getBdczldzS1().endsWith(keyWord))) {
                errMsg = ResponseEnum.BDCXS_BDCZLDZS1_ERROR2.getMsg();
                ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                errorVerifyList.add(errorVerify);
            }
        }
        if (!StringUtil.checkStrLength(invoiceTdyw.getBdczldzXxdz(), 1, 80)) {
            errMsg = ResponseEnum.BDCXS_BDCZLDZXXDZ_ERROR.getMsg();
            ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
            errorVerifyList.add(errorVerify);
        }
        if (Arrays.stream(new String[]{"街", "路", "村", "乡", "镇", "道", "巷", "号"}).noneMatch(keyWord -> invoiceTdyw.getBdczldzXxdz().contains(keyWord))) {
            errMsg = ResponseEnum.BDCXS_BDCZLDZXXDZ_ERROR2.getMsg();
            ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
            errorVerifyList.add(errorVerify);
        }
        if (!StringUtil.checkStrLength(invoiceTdyw.getBdcdwdm(), 0, 28)) {
            errMsg = ResponseEnum.BDCXS_BDCDWDM_ERROR.getMsg();
            ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
            errorVerifyList.add(errorVerify);
        }
        if (!StringUtil.checkStrLength(invoiceTdyw.getWqhtbabh(), 0, 28)) {
            errMsg = ResponseEnum.BDCXS_WQHTBABH_ERROR.getMsg();
            ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
            errorVerifyList.add(errorVerify);
        }
        if (StringUtils.isNotBlank(invoiceTdyw.getBdcdwdm()) && StringUtils.isNotBlank(invoiceTdyw.getWqhtbabh())) {
            errMsg = ResponseEnum.BDCXS_BDCDWDM_WQHTBABH_ERROR.getMsg();
            ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
            errorVerifyList.add(errorVerify);
        }
        if (StringUtils.isBlank(invoiceTdyw.getKdsbz()) || !Pattern.matches("Y|N", invoiceTdyw.getKdsbz())) {
            errMsg = ResponseEnum.BDCXS_KDSBZ_ERROR.getMsg();
            ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
            errorVerifyList.add(errorVerify);
        }
        if (!StringUtil.checkStrLength(invoiceTdyw.getTdzzsxmbh(), 0, 16)) {
            errMsg = ResponseEnum.BDCXS_TDZZSXMBH_ERROR.getMsg();
            ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
            errorVerifyList.add(errorVerify);
        }
        if (invoiceTdyw.getHdjsjg() != null) {
            String hdjsjg = StringUtil.toString(invoiceTdyw.getHdjsjg().stripTrailingZeros().precision());
            if (!StringUtil.checkStrLength(hdjsjg, 0, 18)) {
                errMsg = ResponseEnum.BDCXS_HDJSJG_ERROR.getMsg();
                ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                errorVerifyList.add(errorVerify);
            }
        }
        if (invoiceTdyw.getSjcjhsje() != null) {
            String sjcjhsje = StringUtil.toString(invoiceTdyw.getSjcjhsje().stripTrailingZeros().precision());
            if (!StringUtil.checkStrLength(sjcjhsje, 0, 18)) {
                errMsg = ResponseEnum.BDCXS_SJCJHSJE_ERROR.getMsg();
                ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                errorVerifyList.add(errorVerify);
            }
        }
        if (!StringUtil.checkStrLength(invoiceTdyw.getCqzsbh(), 0, 40)) {
            errMsg = ResponseEnum.BDCXS_CQZSBH_ERROR.getMsg();
            ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
            errorVerifyList.add(errorVerify);
        }
        if (StringUtils.isBlank(invoiceTdyw.getMjdw())) {
            errMsg = ResponseEnum.BDCXS_MJDW_ERROR.getMsg();
            ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
            errorVerifyList.add(errorVerify);
        }
        if (StringUtils.isNotBlank(invoiceTdyw.getMjdw()) && !Pattern.matches("平方米|平方千米|公顷|亩|h㎡|k㎡|㎡", invoiceTdyw.getMjdw())) {
            errMsg = ResponseEnum.BDCXS_MJDW_ERROR2.getMsg();
            ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
            errorVerifyList.add(errorVerify);
        }

        // 多方共同购买标志为Y，校验共同购买方信息
        if (CommonConstant.STR_Y.equals(invoiceTdyw.getDfgtgmbz())) {
            if (CollectionUtil.isEmpty(invoiceTdyw.getTdywItemList())) {
                errMsg = ResponseEnum.BDCXS_GTGMF_EMPTY_ERROR.getMsg();
                ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                errorVerifyList.add(errorVerify);
            } else {
                int number = 1;
                String key2 = "第" + number + "行共同购买方信息";
                for (VmsFullOutInvoiceTdywItem tdywItem : invoiceTdyw.getTdywItemList()) {
                    if (!Pattern.matches("^[\\u4E00-\\u9FA5A-Za-z]+$", tdywItem.getGtgmf())) {
                        errMsg = ResponseEnum.BDCXS_GTGMF_ERROR.getMsg();
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key2, errMsg);
                        errorVerifyList.add(errorVerify);
                    }
                    if (!StringUtil.checkStrLength(tdywItem.getGtgmf(), 1, 100)) {
                        errMsg = ResponseEnum.BDCXS_GTGMF_ERROR2.getMsg();
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key2, errMsg);
                        errorVerifyList.add(errorVerify);
                    }
                    if (!StringUtil.checkStrLength(tdywItem.getZjlx(), 1, 3)) {
                        errMsg = ResponseEnum.BDCXS_ZJLX_ERROR.getMsg();
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key2, errMsg);
                        errorVerifyList.add(errorVerify);
                    }
                    if (!StringUtil.checkStrLength(tdywItem.getZjhm(), 1, 20)) {
                        errMsg = ResponseEnum.BDCXS_ZJHM_ERROR.getMsg();
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key2, errMsg);
                        errorVerifyList.add(errorVerify);
                    }
                    number++;
                }
            }
        }

        return errorVerifyList;
    }

    /**
     * 校验不动产租赁特定业务信息
     * @param num 第几张发票
     * @param invoice 开票数据
     * @return 校验结果
     */
    private List<ErrorVerifyVo> checkBdczl(String num, VmsFullOutInvoiceInfoDto invoice) {
        List<ErrorVerifyVo> errorVerifyList = new ArrayList<>();
        String key = "不动产租赁特定业务信息";
        String errMsg;

        if (CollectionUtil.isEmpty(invoice.getVmsFullOutInvoiceTdywList())) {
            errMsg = ResponseEnum.BDCZL_TDYW_EMPTY_ERROR.getMsg();
            ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
            errorVerifyList.add(errorVerify);
            return errorVerifyList;
        }

        // 不动产租赁服务发票仅支持单行开具
        List<VmsFullOutInvoiceItems> invoiceItemsList = invoice.getVmsFullOutInvoiceItemsList();
        if (CollectionUtil.isNotEmpty(invoiceItemsList)
                && invoiceItemsList.size() != 1) {
            errMsg = ResponseEnum.BDCZL_ITEM_ERROR.getMsg();
            ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
            errorVerifyList.add(errorVerify);
        }
        // 不动产租赁发票，单位、单价、数量必填
        VmsFullOutInvoiceItems invoiceItem = invoiceItemsList.get(0);
        if (StringUtils.isBlank(invoiceItem.getDw()) || StringUtils.isBlank(invoiceItem.getDj())
                || StringUtils.isBlank(invoiceItem.getSl())) {
            errMsg = ResponseEnum.BDCZL_DW_DJ_SL_ERROR.getMsg();
            ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
            errorVerifyList.add(errorVerify);
        }

        // 不动产租赁服务发票的特定业务只有第一条
        VmsFullOutInvoiceTdyw invoiceTdyw = invoice.getVmsFullOutInvoiceTdywList().get(0);

        if (!StringUtil.checkStrLength(invoiceTdyw.getBdczldzS(), 1, 20)) {
            errMsg = ResponseEnum.BDCXS_BDCZLDZS_ERROR.getMsg();
            ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
            errorVerifyList.add(errorVerify);
        }
        if (Arrays.stream(new String[]{"省", "自治区", "特别行政区", "北京市", "天津市", "上海市", "重庆市"}).noneMatch(keyWord -> invoiceTdyw.getBdczldzS().endsWith(keyWord))) {
            errMsg = ResponseEnum.BDCXS_BDCZLDZS_ERROR2.getMsg();
            ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
            errorVerifyList.add(errorVerify);
        }
        if (StrUtil.equalsAny(invoiceTdyw.getBdczldzS(), "香港特别行政区", "澳门特别行政区", "台湾省")) {
            if (!StringUtil.checkStrLength(invoiceTdyw.getBdczldzS1(), 0, 20)) {
                errMsg = ResponseEnum.BDCXS_BDCZLDZS1_ERROR.getMsg();
                ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                errorVerifyList.add(errorVerify);
            }
        } else {
            if (!StringUtil.checkStrLength(invoiceTdyw.getBdczldzS1(), 1, 20)) {
                errMsg = ResponseEnum.BDCXS_BDCZLDZS1_ERROR.getMsg();
                ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                errorVerifyList.add(errorVerify);
            }
        }
        if (StringUtils.isNotBlank(invoiceTdyw.getBdczldzS1())) {
            if (Arrays.stream(new String[]{"市", "盟", "自治州", "地区", "区"}).noneMatch(keyWord -> invoiceTdyw.getBdczldzS1().endsWith(keyWord))) {
                errMsg = ResponseEnum.BDCXS_BDCZLDZS1_ERROR2.getMsg();
                ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                errorVerifyList.add(errorVerify);
            }
        }
        if (!StringUtil.checkStrLength(invoiceTdyw.getBdczldzXxdz(), 1, 80)) {
            errMsg = ResponseEnum.BDCXS_BDCZLDZXXDZ_ERROR.getMsg();
            ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
            errorVerifyList.add(errorVerify);
        }
        if (Arrays.stream(new String[]{"街", "路", "村", "乡", "镇", "道", "巷", "号"}).noneMatch(keyWord -> invoiceTdyw.getBdczldzXxdz().contains(keyWord))) {
            errMsg = ResponseEnum.BDCXS_BDCZLDZXXDZ_ERROR2.getMsg();
            ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
            errorVerifyList.add(errorVerify);
        }
        if (StringUtils.isBlank(invoiceTdyw.getZlqqz())) {
            errMsg = ResponseEnum.BDCZL_ZLQQZ_ERROR.getMsg();
            ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
            errorVerifyList.add(errorVerify);
        }
        if (StringUtils.isNotBlank(invoiceTdyw.getZlqqz()) &&
                !Pattern.matches("\\d{4}-\\d{2}-\\d{2} \\d{4}-\\d{2}-\\d{2}", invoiceTdyw.getZlqqz())) {
            errMsg = ResponseEnum.BDCZL_ZLQQZ_ERROR2.getMsg();
            ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
            errorVerifyList.add(errorVerify);
        }
        if (StringUtils.isBlank(invoiceTdyw.getKdsbz()) || !Pattern.matches("Y|N", invoiceTdyw.getKdsbz())) {
            errMsg = ResponseEnum.BDCXS_KDSBZ_ERROR.getMsg();
            ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
            errorVerifyList.add(errorVerify);
        }
        if (!StringUtil.checkStrLength(invoiceTdyw.getCqzsbh(), 1, 40)) {
            errMsg = ResponseEnum.BDCZL_CQZSBH_ERROR.getMsg();
            ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
            errorVerifyList.add(errorVerify);
        }
        if (StringUtils.isBlank(invoiceTdyw.getMjdw())) {
            errMsg = ResponseEnum.BDCXS_MJDW_ERROR.getMsg();
            ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
            errorVerifyList.add(errorVerify);
        }
        if (StringUtils.isNotBlank(invoiceTdyw.getMjdw()) &&
                !Pattern.matches("平方米|平方千米|公顷|亩|h㎡|k㎡|㎡", invoiceTdyw.getMjdw())) {
            errMsg = ResponseEnum.BDCXS_MJDW_ERROR2.getMsg();
            ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
            errorVerifyList.add(errorVerify);
        }

        return errorVerifyList;
    }

    /**
     * 校验旅客运输特定业务信息
     * @param num 第几张发票
     * @param invoice 开票数据
     * @return 校验结果
     */
    private List<ErrorVerifyVo> checkLkys(String num, VmsFullOutInvoiceInfoDto invoice) {
        List<ErrorVerifyVo> errorVerifyList = new ArrayList<>();
        String key = "旅客运输特定业务信息";
        String errMsg;

        // 旅客运输服务发票仅支持单行开具
        if (CollectionUtil.isNotEmpty(invoice.getVmsFullOutInvoiceItemsList())
                && invoice.getVmsFullOutInvoiceItemsList().size() != 1) {
            errMsg = ResponseEnum.LKYS_ITEM_ERROR.getMsg();
            ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
            errorVerifyList.add(errorVerify);
        }

        // 旅客运输特定业务信息不能为空
        if (CollectionUtil.isEmpty(invoice.getVmsFullOutInvoiceTdywList())) {
            errMsg = ResponseEnum.LKYS_TDYW_EMPTY_ERROR.getMsg();
            ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
            errorVerifyList.add(errorVerify);
            return errorVerifyList;
        }

        // 旅客运输服务发票的特定业务可以有多条
        for (int i = 0; i < invoice.getVmsFullOutInvoiceTdywList().size(); i++) {
            VmsFullOutInvoiceTdyw invoiceTdyw = invoice.getVmsFullOutInvoiceTdywList().get(i);
            key = "第" + (i + 1) + "行旅客信息";
            // 必填项校验
            if (ObjectUtil.isEmpty(invoiceTdyw.getCxrxh()) || ObjectUtil.isEmpty(invoiceTdyw.getCxr())
                    || ObjectUtil.isEmpty(invoiceTdyw.getCxrzjlxdm()) || ObjectUtil.isEmpty(invoiceTdyw.getSfzjhm())
                    || ObjectUtil.isEmpty(invoiceTdyw.getChuxrq()) || ObjectUtil.isEmpty(invoiceTdyw.getCfd())
                    || ObjectUtil.isEmpty(invoiceTdyw.getDdd()) || ObjectUtil.isEmpty(invoiceTdyw.getJtgjlxdm())) {
                errMsg = ResponseEnum.LKYS_TDYW_EMPTY_ERROR2.getMsg();
                ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                errorVerifyList.add(errorVerify);
            }

            if (ObjectUtil.isEmpty(invoiceTdyw.getCxrxh()) || !Pattern.matches("[0-9]{1,8}", invoiceTdyw.getCxrxh().toString())) {
                errMsg = ResponseEnum.LKYS_CXRXH_ERROR.getMsg();
                ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                errorVerifyList.add(errorVerify);
            }
            if (!StringUtil.checkStrLength(invoiceTdyw.getCxr(), 1, 20)) {
                errMsg = ResponseEnum.LKYS_CXR_ERROR.getMsg();
                ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                errorVerifyList.add(errorVerify);
            }
            if (StringUtils.isNotBlank(invoiceTdyw.getCxrzjlxdm())
                    && StringUtils.isBlank(ZjlxEnum.getNameByCode(invoiceTdyw.getCxrzjlxdm()))) {
                errMsg = ResponseEnum.LKYS_CXRZJLXDM_ERROR.getMsg();
                ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                errorVerifyList.add(errorVerify);
            }
            if (!StringUtil.checkStrLength(invoiceTdyw.getSfzjhm(), 1, 20)) {
                errMsg = ResponseEnum.LKYS_SFZJHM_ERROR.getMsg();
                ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                errorVerifyList.add(errorVerify);
            }
            if (StringUtils.isBlank(invoiceTdyw.getChuxrq()) || !invoiceTdyw.getChuxrq().matches("\\d{4}-\\d{2}-\\d{2}")) {
                errMsg = ResponseEnum.LKYS_CXRQ_ERROR.getMsg();
                ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                errorVerifyList.add(errorVerify);
            }
            if (!StringUtil.checkStrLength(invoiceTdyw.getCfd(), 1, 80)) {
                errMsg = ResponseEnum.LKYS_CFD_ERROR.getMsg();
                ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                errorVerifyList.add(errorVerify);
            }
            if (!StringUtil.checkStrLength(invoiceTdyw.getDdd(), 1, 80)) {
                errMsg = ResponseEnum.LKYS_DDD_ERROR.getMsg();
                ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                errorVerifyList.add(errorVerify);
            }
            if (StringUtils.isBlank(invoiceTdyw.getJtgjlxdm())) {
                errMsg = ResponseEnum.LKYS_JTGJLXDM_ERROR.getMsg();
                ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                errorVerifyList.add(errorVerify);
            }
            JtysgjlxEnum jtysgjlx = JtysgjlxEnum.getInstanceCode(invoiceTdyw.getJtgjlxdm());
            if (null == jtysgjlx) {
                errMsg = ResponseEnum.LKYS_JTGJLXDM_ERROR.getMsg();
                ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                errorVerifyList.add(errorVerify);
            } else {
                if (jtysgjlx.getZwdj() != null) {
                    if (StringUtils.isBlank(invoiceTdyw.getZwdj()) || !Arrays.asList(jtysgjlx.getZwdj()).contains(invoiceTdyw.getZwdj())) {
                        errMsg = ResponseEnum.LKYS_ZWDJ_ERROR.getMsg();
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                        errorVerifyList.add(errorVerify);
                    }
                } else if (!StringUtil.checkStrLength(invoiceTdyw.getZwdj(), 0, 20)) {
                    errMsg = ResponseEnum.LKYS_ZWDJ_ERROR2.getMsg();
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, errMsg);
                    errorVerifyList.add(errorVerify);
                }
            }
        }

        return errorVerifyList;
    }

    /**
     * 构建返回错误实体
     */
    private ErrorVerifyVo buildErrorVerify(String num, String key, String value) {
        ErrorVerifyVo errorVerify = new ErrorVerifyVo();
        errorVerify.setNum(num);
        errorVerify.setKey(key);
        errorVerify.setValue(value);
        return errorVerify;
    }

    @Override
    public String checkStringParam(String param, CheckParamEnum checkParamEnum) {
        List<String> errorMsg = new ArrayList<>();

        // 如果字段为空，校验是否必填
        if (StringUtils.isBlank(param)) {
            if (checkParamEnum.getRequired()) {
                errorMsg.add(checkParamEnum.getParamName() + "为必填信息项");
                return String.join("，", errorMsg);
            }
            return String.join("，", errorMsg);
        }

        // 校验是否为固定格式
        if (checkParamEnum.getFixedFormal()) {
            String[] split = param.split("：");
            if (split.length != 2) {
                errorMsg.add(checkParamEnum.getParamName() + "格式不正确，请选择单元格下拉框列表数据");
            }
        }

        // 校验数据最大长度
        if (checkParamEnum.getMaxLength() != 0) {
            if (param.length() > checkParamEnum.getMaxLength()) {
                errorMsg.add(checkParamEnum.getParamName() + "数据不合法,最大长度为" + checkParamEnum.getMaxLength());
            }
        }

        return String.join("，", errorMsg);
    }

    @Override
    public String checkBigDecimalParam(BigDecimal param, CheckParamEnum checkParamEnum) {
        List<String> errorMsg = new ArrayList<>();

        // 如果字段为空，校验是否必填
        if (null == param) {
            if (checkParamEnum.getRequired()) {
                errorMsg.add(checkParamEnum.getParamName() + "为必填信息项");
                return String.join("，", errorMsg);
            }
            return String.join("，", errorMsg);
        }

        // 校验数据整数位和小数位最大长度
        if (StringUtils.isNotBlank(checkParamEnum.getNumberFormat())) {
            String[] split = checkParamEnum.getNumberFormat().split(",");
            if (split.length == 2) {
                // 获取整数位和小数位最大长度
                int maxIntegerDigits = Integer.parseInt(split[0]);
                int maxDecimalDigits = Integer.parseInt(split[1]);
                // 去掉尾部多余的0
                BigDecimal bigDecimal = param.stripTrailingZeros();
                // 获取参数的整数位数和小数位数
                int integerDigits = bigDecimal.precision() - bigDecimal.scale();
                int decimalDigits = Math.max(bigDecimal.scale(), 0);

                // 判断是否满足最大长度限制
                if (integerDigits > maxIntegerDigits || decimalDigits > maxDecimalDigits) {
                    errorMsg.add(checkParamEnum.getParamName() + "数据不合法,整数位最大长度为" + maxIntegerDigits + ",小数位最大长度为" + maxDecimalDigits);
                }
            }
        }

        return String.join("，", errorMsg);
    }
}
